package cc.owoo.godpen.network.http;

import java.util.HashMap;
import java.util.function.BiConsumer;
import java.util.function.Consumer;

/**
 * 携带头的抽象的HTTP报文
 * Created by nimensei
 * 2022-02-25 下午 05:38
 **/
public class AbstractHeader {
    static HashMap<String, HeaderInterceptor> headerInterceptor = new HashMap<>();

    static {
        headerInterceptor.put("user-agent", header -> header.userAgent);
        headerInterceptor.put("content-type", header -> header.contentType);
        headerInterceptor.put("cookie", header -> header.cookie);
    }

    HashMap<String, String> header = new HashMap<>();// 响应头

    final UserAgent userAgent = new UserAgent();// 用户设备标识
    final ContentType contentType = new ContentType();// 内容类型
    final Cookie cookie = new Cookie();// cookie对象

    String encode = HttpUtil.encode;// 传输编码


    /**
     * 将参数恢复到默认
     */
    public void initialize() {
        header.clear();
        userAgent.clear();
        contentType.clear();
        cookie.clear();
        encode = HttpUtil.encode;
    }

    /**
     * 拷贝对象
     *
     * @param abstractHeader 拷贝源
     */
    public void copySetHeader(AbstractHeader abstractHeader) {
        header.clear();
        this.header.putAll(abstractHeader.header);
        this.userAgent.copySet(abstractHeader.userAgent);
        this.contentType.copySet(abstractHeader.contentType);
        this.cookie.copySet(abstractHeader.cookie);
        this.encode = abstractHeader.encode;
    }

    /**
     * 获取响应头
     *
     * @param key 键
     * @return 值
     */
    public String getHeader(String key) {
        if ((key = HttpUtil.formatHeader(key)) == null)
            return null;
        HeaderInterceptor interceptor = headerInterceptor.get(key);
        if (interceptor != null)
            return interceptor.get(this).stringify();
        return header.get(key);
    }

    /**
     * 设置请求头文本
     *
     * @param string 请求头文本
     * @return 设置个数
     */
    int setHeader(String string) {
        if (string == null || string.length() == 0)
            return 0;
        String[] list = string.split("\n");
        int count = 0;
        for (String s : list) {
            int index = s.indexOf(':', 1);
            if (index == -1)
                continue;
            String key = s.substring(0, index).trim();
            String value = s.substring(index + 1).trim();
            if (key.length() == 0 || value.length() == 0)
                continue;
            if (setHeader(key, value))
                ++count;
        }
        return count;
    }

    /**
     * 设置报文头，如果键或值为空，则设置失败，若要设置莫一个键的值为null，请调用removeHeader
     *
     * @param key   键
     * @param value 值
     */
    boolean setHeader(String key, String value) {
        if ((key = HttpUtil.formatHeader(key)) == null || value == null || (value = value.trim()).length() == 0)
            return false;
        HeaderInterceptor interceptor = headerInterceptor.get(key);
        if (interceptor != null)
            interceptor.get(this).parse(value);
        else
            header.put(key, value);
        return true;
    }

    /**
     * 删除报文头，如果键为空，则返回null
     *
     * @param key 键
     * @return 删除的值
     */
    public String removeHeader(String key) {
        if ((key = HttpUtil.formatHeader(key)) == null)
            return null;
        HeaderInterceptor interceptor = headerInterceptor.get(key);
        if (interceptor == null)
            return header.remove(key);
        HeaderProperty<?> property = interceptor.get(this);
        property.clear();
        return null;
    }

    /**
     * 是否包含该键
     *
     * @param key 键
     * @return 是否包含该键
     */
    public boolean containsHeaderKey(String key) {
        if ((key = HttpUtil.formatHeader(key)) == null)
            return false;
        HeaderInterceptor interceptor = headerInterceptor.get(key);
        if (interceptor != null)
            return !interceptor.get(this).isEmpty();
        return header.containsKey(key);
    }

    /**
     * 遍历header的键
     *
     * @param action 遍历接口
     */
    public void forHeaderKey(Consumer<String> action) {
        header.keySet().forEach(action);
        if (!userAgent.isEmpty())
            action.accept(userAgent.headerName);
        if (!contentType.isEmpty())
            action.accept(contentType.headerName);
        if (!cookie.isEmpty())
            action.accept(cookie.headerName);
    }

    /**
     * 遍历header
     *
     * @param action 遍历接口
     */
    public void forHeader(BiConsumer<String, String> action) {
        header.forEach(action);
        if (!userAgent.isEmpty())
            action.accept(userAgent.headerName, userAgent.stringify());
        if (!contentType.isEmpty())
            action.accept(contentType.headerName, contentType.stringify());
        if (!cookie.isEmpty())
            action.accept(cookie.headerName, cookie.stringify());
    }

    /**
     * 获取浏览器标识对象
     *
     * @return 浏览器标识对象
     */
    public UserAgent getUserAgent() {
        return userAgent;
    }

    /**
     * 设置浏览器标识
     *
     * @param string 浏览器标识
     */
    void setUserAgent(String string) {
        userAgent.parse(string);
    }

    /**
     * 获取内容类型对象
     *
     * @return 内容类型对象
     */
    public ContentType getContentType() {
        return contentType;
    }

    /**
     * 设置内容类型
     *
     * @param string 内容类型
     */
    void setContentType(String string) {
        contentType.parse(string);
    }

    /**
     * 获取Cookie
     *
     * @return Cookie对象
     */
    public Cookie getCookie() {
        return cookie;
    }

    /**
     * 设置Cookie
     *
     * @param string Cookie
     */
    void setCookie(String string) {
        cookie.parse(string);
    }

    /**
     * 序列化
     *
     * @param string 需要拼接的字符串
     */
    public void stringifyHeader(StringBuilder string) {
        HttpUtil.stringifyHeader(string, this);
    }

    /**
     * 获取字符串编码
     *
     * @return 字符串编码
     */
    public String getEncode() {
        return encode;
    }

    /**
     * 设置字符串编码
     *
     * @param encode 字符串编码
     */
    public void setEncode(String encode) {
        this.encode = encode;
    }
}
